package kernel

import (
	. "data/datatype"
	"share/msg"
	"util/parser"
	"util/pool"
)

type GameObject struct {
	data     interface{}
	dbid     int64
	objid    ObjectID
	typename string
	del      bool
	capacity int
	parent   GameObjecter
	children pool.PoolList
	namehash int32
	kernel   *Kernel
}

func (bo *GameObject) GetDataType() string {
	return ""
}

func (bo *GameObject) SetParent(p GameObjecter) {
	bo.parent = p
}

func (bo *GameObject) Parent() GameObjecter {
	return bo.parent
}

func (bo *GameObject) SetKernel(kernel *Kernel) {
	bo.kernel = kernel
}

func (bo *GameObject) Kernel() *Kernel {
	return bo.kernel
}

func (bo *GameObject) SetData(data interface{}) {
	bo.data = data
}

func (bo *GameObject) GetName() string {
	return ""
}

func (bo *GameObject) SetNameHash(hash int32) {
	bo.namehash = hash
}

func (bo *GameObject) GetNameHash() int32 {
	return bo.namehash
}

func (bo *GameObject) GetData() interface{} {
	return bo.data
}

func (bo *GameObject) SetDBId(id int64) {
	bo.dbid = id
}

func (bo *GameObject) GetDBId() int64 {
	return bo.dbid
}

func (bo *GameObject) SetType(name string) {
	bo.typename = name
}

func (bo *GameObject) GetType() string {
	return bo.typename
}

func (bo *GameObject) SetObjId(id ObjectID) {
	bo.objid = id
}

func (bo *GameObject) GetObjId() *ObjectID {
	return &bo.objid
}

func (bo *GameObject) GetRegionId() int32 {
	return bo.objid.Region
}

func (bo *GameObject) IsDel() bool {
	return bo.del
}

func (bo *GameObject) Delete() {
	bo.del = true
}

//serialize

//从数据库加载
func (bo *GameObject) LoadFromDB(data *msg.DbPack) {

}

//序列化
func (bo *GameObject) Serialize() *msg.DbPack {
	db := msg.DbPack{}
	db.Dbid = bo.dbid
	db.Data = make([]msg.Objects, 0, 10)
	o, exist := parser.Defs[bo.typename]
	for exist {
		db.Data = append(db.Data, packobj(o, bo.data, bo.dbid == 0))
		if o.Base != "" {
			o, exist = parser.Defs[o.Base]
		} else {
			break
		}
	}

	return &db
}

func packobj(o parser.Object, data interface{}, isnew bool) msg.Objects {

	var out msg.Objects
	if isnew {
		out = create(o, data)
	} else {
		out = update(o, data)
	}
	return out
}

func create(o parser.Object, data interface{}) msg.Objects {
	out := msg.Objects{}
	var err error
	out.Props = make([]msg.PropData, 0, len(o.Propertys))
	for _, p := range o.Propertys {
		if p.Save == "true" {
			pd := msg.PropData{}
			pd.Name = p.Name
			pd.Type = p.Type
			if pp, ok := data.(proppacker); ok {
				pd.Val, err = pp.Get(p.Name)
				if err != nil {
					panic(err)
				}
				out.Props = append(out.Props, pd)
				continue
			}
			panic("property not found")
		}
	}

	out.Records = make([]msg.Record, len(o.Records))
	for _, r := range o.Records {
		if r.Save == "true" {
			rd := msg.Record{}
			rd.Name = r.Name
			rd.Cols = r.Cols
			if opacker, ok := data.(objpacker); ok {
				rec := opacker.GetRec(r.Name)
				if rp, ok2 := rec.(recpacker); ok2 {
					rd.Rows = rp.Rows()
					_, rd.ColType = rp.ColTypes()
					rd.ColData = make([]interface{}, 0, rd.Rows*rd.Cols)
					for i := 0; i < rd.Rows; i++ {
						for j := 0; j < rd.Cols; j++ {
							val, err := rp.Get(i, j)
							if err != nil {
								panic(err)
							}
							rd.ColData = append(rd.ColData, val)
						}
					}

					out.Records = append(out.Records, rd)

				} else {
					panic("pack record error")
				}

			} else {
				panic("pack record error")
			}
		}
	}

	return out
}

func update(o parser.Object, data interface{}) msg.Objects {
	out := msg.Objects{}
	out.Props = make([]msg.PropData, 0, len(o.Propertys))
	if pp, ok := data.(proppacker); ok {
		dirty := pp.GetDirty()
		for name, val := range dirty {
			pd := msg.PropData{}
			pd.Name = name
			pd.Val = val
			_, pd.Type, _ = pp.Type(name)
			out.Props = append(out.Props, pd)
		}
	}

	out.Records = make([]msg.Record, 0, len(o.Records))
	for _, r := range o.Records {
		if r.Save == "true" {
			rd := msg.Record{}
			rd.Name = r.Name
			rd.Cols = r.Cols
			if opacker, ok := data.(objpacker); ok {
				rec := opacker.GetRec(r.Name)
				if rp, ok2 := rec.(recpacker); ok2 {
					if rp.Dirty() {
						rd.Rows = rp.Rows()
						_, rd.ColType = rp.ColTypes()
						rd.ColData = make([]interface{}, 0, rd.Rows*rd.Cols)
						for i := 0; i < rd.Rows; i++ {
							for j := 0; j < rd.Cols; j++ {
								val, err := rp.Get(i, j)
								if err != nil {
									panic(err)
								}
								rd.ColData = append(rd.ColData, val)
							}
						}
						out.Records = append(out.Records, rd)
					}

				} else {
					panic("pack record error")
				}

			} else {
				panic("pack record error")
			}
		}
	}

	return out
}

func CreateGameObject() *GameObject {
	bo := &GameObject{}
	bo.del = false
	return bo
}
